bitkeeper revision 1.160.3.1 (3ea53c71xG2JEZ0LCbFRAxt9kayWBw)
authorach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk>
Tue, 22 Apr 2003 12:58:25 +0000 (12:58 +0000)
committerach61@labyrinth.cl.cam.ac.uk <ach61@labyrinth.cl.cam.ac.uk>
Tue, 22 Apr 2003 12:58:25 +0000 (12:58 +0000)
fix earlier merge problems
user space virtual disk manager

23 files changed:
.rootkeys
tools/vdmanager/build.xml [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Extent.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Library.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Main.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Mode.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Parser.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Partition.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/PartitionManager.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualBlockDevice.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDisk.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDiskManager.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XML.java [new file with mode: 0755]
tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XMLHelper.java [new file with mode: 0755]
tools/vdmanager/vdmanager [new file with mode: 0755]
xen/drivers/block/xen_block.c
xen/drivers/block/xen_segment.c
xen/drivers/ide/ide-disk.c
xen/include/xeno/sched.h
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_block.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/block/xl_segment_proc.c
xenolinux-2.4.21-pre4-sparse/drivers/block/genhd.c [new file with mode: 0644]

index 5cfbe6a9aab33aa74f4359a5385ede5dfbf512d1..812a71f6ed57a8e633e9eb03483c3a2849c5c974 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3e71afadoAI0VvAGKebLpToVQxUKfQ tools/domain_builder/mynewdom
 3e4d0046VHhXwFuG5FK34AVxqd5A_A tools/domain_builder/newdom
 3e4d0046IBzDIeaMbQB-e2QB2ahbig tools/domain_builder/vifinit
+3ea53c6dz47kAOwpk54f8_zOAQ5ngw tools/vdmanager/build.xml
+3ea53c6dE-azH1i1VJmJMp9SHnETkQ tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Extent.java
+3ea53c6dtqvqC3gxeAjzmSwkYsowIw tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Library.java
+3ea53c6dVva2nmEP3TNM37RmshYJ1g tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Main.java
+3ea53c6dF_CltZw3zVG3-R76tMlhMA tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Mode.java
+3ea53c6dpDHzX93WBQXulAmm85Njzw tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Parser.java
+3ea53c6d5Rgb_r3sSpgpgP-LEn423Q tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Partition.java
+3ea53c6d2dbw9PQT8bGwFUIFIeVhGA tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/PartitionManager.java
+3ea53c6dSKVeFlBS7VwTO38BCueHBQ tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualBlockDevice.java
+3ea53c6dCSPB23LMsHvf44Pp6WL2Pg tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDisk.java
+3ea53c6d48QGVkviHh0jBB_h_ZqZDw tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDiskManager.java
+3ea53c6efdL6CPTu_z5b_MxlxTdX_Q tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XML.java
+3ea53c6ek5CbDZbBF3513sZKa5W3cQ tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XMLHelper.java
+3ea53c6eKECrbeZtdlbaR1zcBwn94A tools/vdmanager/vdmanager
 3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
 3ddb79bcCa2VbsMp7mWKlhgwLQUQGA xen/README
 3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
 3e5a4e66U45cAIoHmxg0y1e1XhzVCA xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/mmu_context.c
 3e5a4e66qRlSTcjafidMB6ulECADvg xenolinux-2.4.21-pre4-sparse/arch/xeno/vmlinux.lds
 3e5a4e668yELUdtr3HiJZBIqxqUyuA xenolinux-2.4.21-pre4-sparse/drivers/block/Config.in
+3ea53c6em6uzVHSiGqrbbAVofyRY_g xenolinux-2.4.21-pre4-sparse/drivers/block/genhd.c
 3e5a4e66mrtlmV75L1tjKDg8RaM5gA xenolinux-2.4.21-pre4-sparse/drivers/block/ll_rw_blk.c
 3e5a4e66rw65CxyolW9PKz4GG42RcA xenolinux-2.4.21-pre4-sparse/drivers/char/tty_io.c
 3e5a4e669uzIE54VwucPYtGwXLAbzA xenolinux-2.4.21-pre4-sparse/fs/exec.c
diff --git a/tools/vdmanager/build.xml b/tools/vdmanager/build.xml
new file mode 100755 (executable)
index 0000000..5a76a48
--- /dev/null
@@ -0,0 +1,45 @@
+<project name="vdmanager project" default="compile">
+  <property name="src" location="src"/>
+  <property name="build" location="build"/>
+  <property name="dist" location="dist"/>
+  <property name="lib" location="lib"/>
+
+  <target name="init">
+    <tstamp/>
+    <mkdir dir="${build}"/>     
+  </target>
+
+  <target name="compile" depends="init">
+    <javac srcdir="${src}" destdir="${build}" debug="on"/>
+  </target>
+
+  <target name="dist" depends="compile">
+    <jar jarfile="vdmanager.jar"
+         excludes="*~"
+        basedir="${build}">
+      <fileset dir="${src}" />
+      <fileset dir=".">
+        <include name="build.xml"/>
+        <include name="vdmanager"/>
+      </fileset>
+      <manifest>
+        <attribute name="Built-By" value="${user.name}"/>
+       <attribute name="Main-Class" value="uk.ac.cam.cl.xeno.vdmanager.Main"/>
+       <attribute name="Sealed" value="true"/>
+      </manifest>
+    </jar>
+  </target>
+
+  <target name="test" depends="compile">
+    <java fork="true" classname="uk.ac.cam.cl.xeno.vdmanager.Main">
+      <classpath>
+        <pathelement path="${build}"/>
+      </classpath>
+    </java>
+  </target>
+
+  <target name="clean">
+    <delete dir="${build}"/>
+    <delete dir="${lib}"/>
+  </target>
+</project>
\ No newline at end of file
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Extent.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Extent.java
new file mode 100755 (executable)
index 0000000..048a381
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Extent.java
+ * 03.03.26 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+public class
+Extent
+{
+  int disk;
+  long offset;                                           /* offset into disk */
+  long size;                      /* size of this extent in 512 byte sectors */
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Library.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Library.java
new file mode 100755 (executable)
index 0000000..0709376
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Library.java
+ * 03.03.28 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+public class
+Library
+{
+  /*
+   * convert a number to a fixed width string
+   */
+  static String
+  format (long input, int width, int prefix)
+  {
+    String sss = Long.toString(input);
+    String space = "                                ";
+
+    if (width < sss.length())
+    {
+      width = sss.length();
+    }
+
+    if (prefix == 0)
+    {
+      return space.substring(0, width - sss.length()) + sss;
+    }
+    else
+    {
+      return sss + space.substring(0, width - sss.length());
+    }
+  }
+
+  /*
+   * convert a string to a fixed width string
+   */
+  static String
+  format (String input, int width, int prefix)
+  {
+    String space = "                                ";
+
+    if (width < input.length())
+    {
+      width = input.length();
+    }
+
+    if (prefix == 0)
+    {
+      return space.substring(0, width - input.length()) + input;
+    }
+    else
+    {
+      return input + space.substring(0, width - input.length());
+    }
+  }
+
+  /*
+   * convert a number (string format) into 
+   * the corresponding integer value.
+   */
+  static int
+  parse_size(String size)
+  {
+    String substring = size;
+    int    suffix = 1;
+
+    if ((substring = check(size, 'm')) != null)
+    {
+      suffix = 1024 * 1024;
+    }
+    else if ((substring = check(size, 'M')) != null)
+    {
+      suffix = 1024 * 1024;
+    }
+    else if ((substring = check(size, 'k')) != null)
+    {
+      suffix = 1024;
+    }
+    else if ((substring = check(size, 'K')) != null)
+    {
+      suffix = 1024;
+    }
+    else if ((substring = check(size, 'g')) != null)
+    {
+      suffix = 1024 * 1024 * 1024;
+    }
+    else if ((substring = check(size, 'G')) != null)
+    {
+      suffix = 1024 * 1024 * 1024;
+    }
+    else
+    {
+      substring = size;
+    }
+
+    return Integer.decode(substring).intValue() * suffix;
+  }
+
+  static String
+  check(String size, char suffix)
+  {
+    int index = size.indexOf(suffix);
+
+    if (index != -1)
+    {
+      return size.substring(0, index);
+    }
+    else
+    {
+      return null;
+    }
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Main.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Main.java
new file mode 100755 (executable)
index 0000000..2a036bb
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Main.java
+ * 03.03.26 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.util.Date;
+
+public class
+Main
+{
+  static String state_filename_in  = "/var/run/vdmanager.xml";
+  static String state_filename_out = "/var/run/vdmanager.xml";
+  static String partition_filename = "/proc/partitions";
+
+  void
+  go (String[] argv)
+  {
+    PartitionManager pm = new PartitionManager(partition_filename);
+    VirtualDiskManager vdm = new VirtualDiskManager();;
+    Parser parser = new Parser(pm, vdm);
+
+    XML.load_state(pm, vdm, state_filename_in);
+    parser.parse_main(argv);
+    XML.dump_state(pm, vdm, state_filename_out);
+  }
+
+  public static void
+  main (String[] argv)
+  {
+    Main foo = new Main();
+    foo.go(argv);
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Mode.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Mode.java
new file mode 100755 (executable)
index 0000000..70e66f6
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Mode.java
+ * 03.03.27 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+public class 
+Mode 
+{
+  private final String name;
+
+  private Mode(String name) { this.name = name; }
+
+  public String toString()  { return name; }
+
+  public static final Mode READ_ONLY  = new Mode("ro");
+  public static final Mode READ_WRITE = new Mode("rw");
+}
+
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Parser.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Parser.java
new file mode 100755 (executable)
index 0000000..0ce703a
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Parser.java
+ * 03.03.27 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.Date;
+
+public class
+Parser
+{
+  static String prompt = "vdmanager> ";
+  static String default_addpartition_chunksize = "104857600";        /* 100M */
+  static int    default_sector_size = 512;
+
+  PartitionManager pm;
+  VirtualDiskManager vdm;
+
+  Parser (PartitionManager pm, VirtualDiskManager vdm)
+  {
+    this.pm = pm;
+    this.vdm = vdm;
+  }
+
+  void
+  parse_main (String[] argv)
+  {
+    if (argv.length == 0)
+    {
+      parse_input(null);
+    }
+    else
+    {
+      parse_commandline(argv);
+    }
+  }
+
+  void
+  parse_input (String filename)
+  {
+    String line;
+    BufferedReader in;
+
+    if (filename != null)
+    {
+      try
+      {
+       in = new BufferedReader(new FileReader(filename));
+      }
+      catch (FileNotFoundException fnfe)
+      {
+       System.err.println (fnfe);
+       return;
+      }
+    }
+    else
+    {
+      in = new BufferedReader(new InputStreamReader(System.in));
+    }
+
+    try
+    {
+      if (filename == null)
+      {
+       System.out.print (prompt);
+      }
+      line = in.readLine();
+      while (line != null)
+      {
+       StringTokenizer st = new StringTokenizer(line);
+       Vector v = new Vector();
+
+       while (st.hasMoreTokens()) 
+       {
+         v.add(st.nextToken());
+       }
+
+       if (parse_commandline((String[]) v.toArray(new String[v.size()])))
+       {
+         return;
+       }
+       
+       if (filename == null)
+       {
+         System.out.print (prompt);
+       }
+       line = in.readLine();
+      }
+    }
+    catch (IOException ioe)
+    {
+      System.err.println(ioe);
+    }
+
+    if (filename == null)
+    {
+      System.out.println ("");
+    }
+    return;
+  }
+
+  boolean
+  parse_commandline (String[] commands)
+  {
+    if (commands.length == 0)
+    {
+      return false;
+    }
+
+    String keyword = commands[0].toLowerCase();
+    if (keyword.equals("file"))
+    {
+      if (commands.length < 2)
+      {
+       System.out.println ("file [filename]");
+       return false;
+      }
+      for (int i = 1; i < commands.length; i++)
+      {
+       System.out.println ("file " + commands[i]);
+       parse_input(commands[i]);
+      }
+    }
+    else if (keyword.equals("show"))
+    {
+      parse_show(commands);
+    }
+    else if (keyword.equals("addpartition"))
+    {
+      parse_addpartition(commands);
+    }
+    else if (keyword.equals("vdcreate"))
+    {
+      parse_vdcreate(commands);
+    }
+    else if (keyword.equals("vddelete"))
+    {
+      parse_vddelete(commands);
+    }
+    else if (keyword.equals("vdrefresh"))
+    {
+      parse_vdrefresh(commands);
+    }
+    else if (keyword.equals("vbdcreate"))
+    {
+      parse_vbdcreate(commands);
+    }
+    else if (keyword.equals("vbddelete"))
+    {
+      parse_vbddelete(commands);
+    }
+    else if (keyword.equals("vbdflush"))
+    {
+      vdm.flush_virtual_block_devices();
+    }
+    else if (keyword.equals("load"))
+    {
+      if (commands.length < 2)
+      {
+       System.out.println ("load <filename>");
+       return false;
+      }
+      XML.load_state (pm, vdm, commands[1]);
+    }
+    else if (keyword.equals("save"))
+    {
+      if (commands.length < 2)
+      {
+       System.out.println ("save <filename>");
+       return false;
+      }
+      XML.dump_state (pm, vdm, commands[1]);
+    }
+    else if (keyword.equals("help") ||
+            keyword.equals("?"))
+    {
+      parse_help();
+    }
+    else if (keyword.equals("exit") ||
+            keyword.equals("quit"))
+    {
+      return true;
+    }
+    else
+    {
+      System.out.println ("unknown command [" + commands[0] + "]. " +
+                         "try \"help\"");
+    }
+    return false;
+  }
+
+  void
+  parse_vdcreate (String[] commands)
+  {
+    VirtualDisk vd;
+
+    if (commands.length < 4)
+    {
+      System.out.println ("vdcreate name size expiry");
+      return;
+    }
+
+    vd = vdm.create_virtual_disk(commands[1],
+                    Library.parse_size(commands[2]) / default_sector_size,
+                                new Date());
+
+    System.out.println ("Virtual Disk created with key: " + vd.get_key());
+  }
+
+  void
+  parse_vddelete (String[] commands)
+  {
+    if (commands.length < 2)
+    {
+      System.out.println ("vddelete key");
+      return;
+    }
+
+    vdm.delete_virtual_disk(commands[1]);
+  }
+
+  void
+  parse_vdrefresh (String[] commands)
+  {
+    if (commands.length < 3)
+    {
+      System.out.println ("vdrefresh key expiry");
+      return;
+    }
+
+    vdm.refresh_virtual_disk(commands[1],
+                            new Date());
+  }
+
+  void
+  parse_vbdcreate (String[] commands)
+  {
+    VirtualDisk vd;
+    VirtualBlockDevice vbd;
+
+    if (commands.length < 4)
+    {
+      System.out.println ("vbdcreate <key> <domain number> <vbd number>");
+      return;
+    }
+
+    if (commands.length == 4)
+    {
+      vbd =
+      vdm.create_virtual_block_device(commands[1],
+                                     Integer.decode(commands[2]).intValue(),
+                                     Integer.decode(commands[3]).intValue(),
+                                     "rw");
+    }
+    else
+    {
+      vbd =
+      vdm.create_virtual_block_device(commands[1],
+                                     Integer.decode(commands[2]).intValue(),
+                                     Integer.decode(commands[3]).intValue(),
+                                     commands[4]);
+    }
+
+    {
+      vd = vdm.get_virtual_disk_key(commands[1]);
+      System.out.println ("\n" + vd.dump_xen(vbd) + "\n");
+    }
+  }
+
+  void
+  parse_vbddelete (String[] commands)
+  {
+    if (commands.length < 3)
+    {
+      System.out.println ("vbdcreate <domain number> <vbd number>");
+      return;
+    }
+
+    vdm.delete_virtual_block_device(Integer.decode(commands[1]).intValue(),
+                                   Integer.decode(commands[2]).intValue());
+  }
+
+  static String show_helptxt = "show <partitions | free | vd [vd number] | vbd>";
+  void
+  parse_show (String[] commands)
+  {
+    String subword;
+      
+    if (commands.length < 2)
+    {
+      System.out.println (show_helptxt);
+      return;
+    }
+
+    subword = commands[1].toLowerCase();
+    if (subword.equals("partition") ||
+       subword.equals("partitions"))
+    {
+      System.out.println(pm.dump(true));
+    }
+    else if (subword.equals("vd"))
+    {
+      String text;
+
+      if (commands.length < 3)
+      {
+       System.out.println(vdm.dump_virtualdisks());
+       return;
+      }
+      text = vdm.dump_virtualdisk(Integer.decode(commands[2]).intValue());
+      if (text == null)
+      {
+       System.out.println("show vd error: invalid virtual disk number");
+      }
+      else
+      {
+       System.out.println(text);
+      }
+    }
+    else if (subword.equals("vbd"))
+    {
+      System.out.println(vdm.dump_virtualblockdevices());
+    }
+    else if (subword.equals("free"))
+    {
+      System.out.println(vdm.dump_free());
+    }
+    else
+    {
+      System.out.println (show_helptxt);
+      return;
+    }
+  }
+
+  void
+  parse_addpartition(String[] commands)
+  {
+    String chunksize = default_addpartition_chunksize;
+
+    if (commands.length > 3 || commands.length < 2)
+    {
+      System.out.println ("addpartition <partition number> [chunksize]");
+      return;
+    }
+    if (commands.length == 3)
+    {
+      chunksize = commands[2];
+    }
+
+    System.out.println ("add partition " + commands[1] + " " + chunksize);
+
+    vdm.add_xeno_partition(pm.get_partition(Integer.parseInt(commands[1])), 
+                          Library.parse_size(chunksize)/default_sector_size);
+    pm.add_xeno_partition(pm.get_partition(Integer.parseInt(commands[1])));
+  }
+
+  void
+  parse_help()
+  {
+    System.out.println ("file <filename>     " +
+                       "read the contents of a file as input to vdmanager");
+    System.out.println ("addpartition <partition number> [chunksize]");
+    System.out.println ("                    " +
+                       "add a partition as a xeno partition");
+    System.out.println ("vdcreate <name> <size> <expiry>");
+    System.out.println ("                    " +
+                       "create a new virtual disk");
+    System.out.println ("vddelete <key>      " +
+                       "delete a virtual disk");
+    System.out.println ("vdrefresh <key> <expiry>");
+    System.out.println ("                    " +
+                       "reset virtual disk expiry");
+    System.out.println ("vbdcreate <key> <domain number> <vbd number> [rw|ro]");
+    System.out.println ("                    " +
+                       "create a new virtual block device");
+    System.out.println ("vbddelete <domain number> <vbd number>");
+    System.out.println ("                    " +
+                       "delete a new virtual block device");
+    System.out.println ("vbdflush            " +
+                       "remove all virtual block devices");
+    System.out.println ("show partitions     " +
+                       "display a complete list of disk partitions");
+    System.out.println ("show vd <vd number> " +
+                       "display virtual disk information");
+    System.out.println ("show vbd            " +
+                       "display virtual virtual block device list");
+    System.out.println ("show free           " +
+                       "display details about unallocated space");
+    System.out.println ("load <filename>     " +
+                       "load new state from file");
+    System.out.println ("save <filename>     " +
+                       "save state to file");
+    System.out.println ("help                " +
+                       "display this help message");
+    System.out.println ("quit                " +
+                       "exit");
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Partition.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Partition.java
new file mode 100755 (executable)
index 0000000..eacb5b6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * PartitionManager.java
+ * 03.03.26 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.io.*;
+
+public class
+Partition
+{
+  int major;
+  int minor;
+  long blocks;
+  long start_sect;
+  long nr_sects;
+  String name;
+
+  boolean 
+  identical (Partition p)
+  {
+    return (major == p.major &&
+           minor == p.minor &&
+           blocks == p.blocks &&
+           start_sect == p.start_sect &&
+           nr_sects == p.nr_sects &&
+           name.equals(p.name));
+  }
+
+  Partition
+  duplicate ()
+  {
+    Partition p = new Partition();
+
+    p.major = major;
+    p.minor = minor;
+    p.blocks = blocks;
+    p.start_sect = start_sect;
+    p.nr_sects = nr_sects;
+    p.name = name;
+
+    return p;
+  }
+
+  String 
+  dump (boolean title)
+  {
+    if (title)
+    {
+      return ("maj:min " + 
+             "    blocks " +
+             "start sect " +
+             " num sects " +
+             "name");
+    }
+    else
+    {
+      return (Library.format(major,3,0) + ":" + 
+             Library.format(minor,3,1) + " " +
+             Library.format(blocks,10,0) + " " +
+             Library.format(start_sect,10,0) + " " +
+             Library.format(nr_sects,10,0) + " " +
+             Library.format(name,7,1));
+    }
+  }
+
+  void
+  dump_xml(PrintWriter out)
+  {
+    out.println ("  <partition>\n" +
+                "    <major>" + major + "</major>\n" +
+                "    <minor>" + minor + "</minor>\n" +
+                "    <blocks>" + blocks + "</blocks>\n" +
+                "    <start_sect>" + start_sect + "</start_sect>\n" +
+                "    <nr_sects>" + nr_sects + "</nr_sects>\n" +
+                "    <name>" + name + "</name>\n" +
+                "  </partition>");
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/PartitionManager.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/PartitionManager.java
new file mode 100755 (executable)
index 0000000..72f5982
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * PartitionManager.java
+ * 03.03.26 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.io.*;
+import java.util.Vector;
+
+public class
+PartitionManager
+{
+  Vector partition_map;
+  Vector xeno_partition_list;
+
+  /*
+   * Initialize partition manager with source file.
+   * Normally we read from /proc/partitions, but we can
+   * specify an alternative file for debugging
+   */
+  PartitionManager (String filename)
+  {
+    String str;
+    BufferedReader in;
+
+    partition_map = new Vector(100,10);
+    xeno_partition_list = new Vector(10,5);
+
+    try
+    {
+      in = new BufferedReader(new FileReader(filename));
+
+      str = in.readLine();                                  /* skip headings */
+      str = in.readLine();                                /* skip blank line */
+
+      str = in.readLine();
+      while (str != null)
+      {
+       Partition partition = new Partition();
+
+       partition.major = Integer.parseInt(str.substring(0,5).trim());
+       partition.minor = Integer.parseInt(str.substring(5,10).trim());
+       partition.blocks = Integer.parseInt(str.substring(10,21).trim());
+       partition.start_sect = Integer.parseInt(str.substring(21,32).trim());
+       partition.nr_sects = Integer.parseInt(str.substring(32,43).trim());
+       partition.name = str.substring(43).trim();
+
+       partition_map.add(partition);
+       str = in.readLine();
+      }
+    }
+    catch (IOException io)
+    {
+      System.err.println ("PartitionManager: error reading partition file [" 
+                         + filename + "]");
+      System.err.println (io);
+    }
+  }
+
+  Partition
+  get_partition (int index)
+  {
+    return (Partition) partition_map.get(index);
+  }
+
+  void
+  add_xeno_partition (Partition partition)
+  {
+    Partition xeno_partition = (Partition) partition.duplicate();
+
+    xeno_partition_list.add(xeno_partition);
+  }
+
+  /*
+   * dump the xeno partition list as xml
+   */
+  void
+  dump_xml (PrintWriter out)
+  {
+    int loop;
+
+    out.println("<partitions>");
+    for (loop = 0; loop < xeno_partition_list.size(); loop++)
+    {
+      Partition partition = (Partition) xeno_partition_list.get(loop);
+      partition.dump_xml(out);
+    }
+    out.println("</partitions>");
+
+    return;
+  }
+
+  /*
+   * dump the partition map as a string
+   * mark: mark the current xeno partitions in the partition map
+   */
+  String
+  dump (boolean mark)
+  {
+    int loop, idx;
+    StringBuffer sb = new StringBuffer();
+    Partition partition;
+
+    for (idx = 0; idx < partition_map.size(); idx++)
+    {
+      boolean xeno_partition = false;
+
+      partition = (Partition) partition_map.get(idx);
+
+      /* is this a xeno partition */
+      if (mark)
+      {
+       for (loop = 0; loop < xeno_partition_list.size(); loop++)
+       {
+         if (partition.identical((Partition)xeno_partition_list.get(loop)))
+         {
+           xeno_partition = true;
+           break;
+         }
+       }
+      }
+
+      if (idx == 0)
+      {
+       sb.append(" idx " + partition.dump(true) + "\n");
+      }
+      if (xeno_partition)
+      {
+       sb.append("[ ");
+      }
+      else
+      {
+       sb.append("  ");
+      }
+      sb.append(Library.format(idx,2,0) + " " + partition.dump(false));
+      if (xeno_partition)
+      {
+       sb.append("]\n");
+      }
+      else
+      {
+       sb.append("\n");
+      }
+    }
+
+    return sb.toString();
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualBlockDevice.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualBlockDevice.java
new file mode 100755 (executable)
index 0000000..a841ca7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * VirtualBlockDevice.java
+ * 03.03.27 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.io.PrintWriter;
+
+public class
+VirtualBlockDevice
+{
+  String key;
+  int domain;
+  int vbdnum;
+  Mode mode;                                                     /* rw or ro */
+
+  String
+  dump (boolean title)
+  {
+    StringBuffer sb = new StringBuffer();
+    int loop;
+
+    if (title)
+    {
+      sb.append("  key         dom vbd mode\n");
+    }
+    else
+    {
+      sb.append("  " + key + "  " +
+               Library.format(domain,3,0) + " " + 
+               Library.format(vbdnum,3,0) + " " + 
+               mode.toString() + "\n");
+    }
+
+    return sb.toString();
+  }
+
+  void
+  dump_xml (PrintWriter out)
+  {
+    out.println("  <virtual_block_device>");
+    out.println("    <key>" + key + "</key>");
+    out.println("    <domain>" + domain + "</domain>");
+    out.println("    <vbdnum>" + vbdnum + "</vbdnum>");
+    out.println("    <mode>" + mode + "</mode>");
+    out.println("  </virtual_block_device>");
+
+    return;
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDisk.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDisk.java
new file mode 100755 (executable)
index 0000000..72d5bb9
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * VirtualDisk.java
+ * 03.03.26 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.util.Date;
+import java.util.Vector;
+import java.lang.Math;
+import java.io.PrintWriter;
+
+public class
+VirtualDisk
+{
+  String name;
+  String key;
+  Date   expiry;
+  Vector extents;
+
+  VirtualDisk (String name, Date expiry, String key)
+  {
+    this.name = name;
+    this.key = key;
+    this.expiry = expiry;
+    extents = new Vector();
+  }
+
+  VirtualDisk (String name)
+  {
+    this (name, null, null);
+    this.key = generate_key();
+    extents = new Vector();
+
+    return;
+  }
+
+  VirtualDisk (String name, Date expiry)
+  {
+    this(name, expiry, null);
+    this.key = generate_key();
+  }
+
+  /*
+   * generate a unique key for this virtual disk.
+   * for now, just generate a 10 digit number
+   */
+  String
+  generate_key ()
+  {
+    return Long.toString(1000000000l + (long)(Math.random() * 8999999999l));
+  }
+
+  String
+  get_key ()
+  {
+    return key;
+  }
+
+  Date
+  get_expiry ()
+  {
+    return expiry;
+  }
+  
+  void
+  set_expiry (Date expiry)
+  {
+    this.expiry = expiry;
+  }
+
+  public void
+  add_extent (Extent extent)
+  {
+    extents.add(extent);
+  }
+
+  public Extent
+  remove_extent ()
+  {
+    Extent e;
+
+    if (extents.size() > 0)
+    {
+      e = (Extent) extents.remove(0);
+    }
+    else
+    {
+      e = null;
+    }
+
+    return e;
+  }
+
+  String
+  dump (boolean details, boolean title)
+  {
+    StringBuffer sb = new StringBuffer();
+    int loop;
+
+    if (details)
+    {
+      if (title)
+      {
+       sb.append("  name: " + name   + "\n");
+       sb.append("   key: " + key    + "\n");
+       sb.append("expiry: " + expiry + "\n");
+       sb.append("\n");
+      }
+      sb.append("   idx  disk    offset      size \n");
+      for (loop = 0; loop < extents.size(); loop++)
+      {
+       Extent e = (Extent) extents.get(loop);
+       sb.append("  " + 
+                 Library.format(loop,3,0) + " " +
+                 Library.format(e.disk,6,0) +
+                 Library.format(e.offset,10,0) +
+                 Library.format(e.size,10,0) + "\n");
+      }
+    }
+    else
+    {
+      if (title)
+      {
+       sb.append("  key         expiry                        name\n");
+      }
+      else
+      {
+       sb.append("  " + key + "  " + expiry.toString() + "  " + name + "\n");
+      }
+    }
+
+    return sb.toString();
+  }
+
+  String
+  dump_xen (VirtualBlockDevice vbd)
+  {
+    StringBuffer sb = new StringBuffer();
+
+    sb.append("domain:" + vbd.domain + " " +
+             vbd.mode.toString() + " " +
+             "segment:" + vbd.vbdnum + " " +
+             "extents:" + extents.size() + " ");
+    for (int loop = 0; loop < extents.size(); loop++)
+    {
+      Extent e = (Extent) extents.get(loop);
+      sb.append("(disk:" + e.disk + " " +
+               "offset:" + e.offset + " " +
+               "size:" + e.size + ")");
+    }
+    return sb.toString();
+  }
+
+  void
+  dump_xml (PrintWriter out)
+  {
+    out.println("  <virtual_disk>");
+    out.println("    <name>" + name + "</name>");
+    out.println("    <key>" + key + "</key>");
+    if (expiry == null)
+    {
+      out.println("    <expiry>0</expiry>");
+    }
+    else
+    {
+      out.println("    <expiry>" + expiry.getTime() + "</expiry>");
+    }
+    out.println("    <extents>");
+    for (int loop = 0; loop < extents.size(); loop++)
+    {
+      Extent e = (Extent) extents.get(loop);
+      out.println("      <extent>");
+      out.println("        <disk>" + e.disk + "</disk>");
+      out.println("        <size>" + e.size + "</size>");
+      out.println("        <offset>" + e.offset + "</offset>");
+      out.println("      </extent>");
+    }
+    out.println("    </extents>");
+    out.println("  </virtual_disk>");
+
+    return;
+  }
+
+  /*
+   * Add a partition as a XenoPartition.
+   * Chop the partition in to extents and of size "size" sectors
+   * and add them to the virtual disk.
+   */
+
+  void
+  add_new_partition (Partition partition, int size)
+  {
+    int loop;
+
+    for (loop = 0; loop < partition.nr_sects / size; loop++)
+    {
+      Extent extent = new Extent();
+
+      extent.disk = partition.major << 8;
+      extent.disk = extent.disk | (partition.minor >> 5) << 5;
+      extent.size = size;
+      extent.offset = partition.start_sect + (size * loop);
+
+      add_extent(extent);
+    }
+    
+    return;
+  }
+  
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDiskManager.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/VirtualDiskManager.java
new file mode 100755 (executable)
index 0000000..eeaa156
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * VirtualDiskManager.java
+ * 03.03.26 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Date;
+import java.io.PrintWriter;
+
+public class
+VirtualDiskManager
+{
+  VirtualDisk free;
+  Vector virtual_disks;
+  Hashtable virtual_block_devices;
+  Hashtable key_hash;
+
+  VirtualDiskManager ()
+  {
+    free = new VirtualDisk("free");
+
+    virtual_disks = new Vector(10,5);
+    flush_virtual_block_devices();
+    key_hash = new Hashtable(100);
+  }
+
+  public VirtualDisk
+  get_virtual_disk_key (String key)
+  {
+    return ((VirtualDisk) key_hash.get(key));
+  }
+
+  public void
+  add_xeno_partition (Partition partition, int size)
+  {
+    free.add_new_partition (partition, size);
+    return;
+  }
+
+  /*
+   * create a new virtual disk
+   */
+
+  public VirtualDisk
+  create_virtual_disk(String name, int size, Date expiry)
+  {
+    VirtualDisk vd = new VirtualDisk (name, expiry);
+
+    while (size > 0)
+    {
+      Extent e;
+
+      e = free.remove_extent();
+      if (e == null)
+      {
+       return null;
+      }
+      size -= e.size;
+      vd.add_extent(e);
+    }
+
+    add_virtual_disk(vd);
+
+    return vd;
+  }
+
+  /*
+   * delete a new virtual disk.  extents go back into the free pool
+   */
+
+  public void
+  delete_virtual_disk (String key)
+  {
+    VirtualDisk vd;
+
+    vd = (VirtualDisk) key_hash.get(key);
+    if (vd != null)
+    {
+      Extent e;
+
+      key_hash.remove(key);
+      virtual_disks.remove(vd);
+
+      e = vd.remove_extent();
+      while (e != null)
+      {
+       free.add_extent(e);
+       e = vd.remove_extent();
+      }
+    }
+    return;
+  }
+
+  /*
+   * reset the expiry time for a virtual disk
+   */
+
+  public void
+  refresh_virtual_disk (String key, Date expiry)
+  {
+    VirtualDisk vd = (VirtualDisk) key_hash.get(key);
+    if (vd != null)
+    {
+      vd.set_expiry(expiry);
+    }
+  }
+
+  /*
+   * create a new virtual block device
+   */
+  public VirtualBlockDevice
+  create_virtual_block_device (String key, int domain, int vbd_num, 
+                              String mode)
+  {
+    VirtualBlockDevice vbd = new VirtualBlockDevice();
+    VirtualDisk vd = get_virtual_disk_key(key);
+
+    if (vd == null)
+    {
+      System.err.println("create virtual block device error: unknown key " +
+                        "[" + key + "]");
+      return null;
+    }
+
+    vbd.key = key;
+    vbd.domain = domain;
+    vbd.vbdnum = vbd_num;
+
+    if (mode.equals(Mode.READ_ONLY.toString()) ||
+       mode.equals("RO") ||
+       mode.equals("ro"))
+    {
+      vbd.mode = Mode.READ_ONLY;
+    }
+    else if (mode.equals(Mode.READ_WRITE.toString()) ||
+            mode.equals("RW") ||
+            mode.equals("rw"))
+    {
+      vbd.mode = Mode.READ_WRITE;
+    }
+    else
+    {
+      System.err.println("create virtual block device error: unknown mode " +
+                        "[" + mode + "]");
+      return null;
+    }
+
+    add_virtual_block_device(vbd);
+
+    return vbd;
+  }
+
+  /*
+   * delete a virtual block device 
+   */
+  public void
+  delete_virtual_block_device (int domain, int vbd_num)
+  {
+    Object hash = get_vbd_hash(domain, vbd_num);
+    VirtualBlockDevice vbd = (VirtualBlockDevice)virtual_block_devices.remove(hash);
+    return;
+  }
+
+  /*
+   * flush all virtual block devices
+   */
+  public void
+  flush_virtual_block_devices ()
+  {
+                            /* isn't automatic garbage collection wonderful? */
+    virtual_block_devices = new Hashtable(100);
+  }
+
+  public void
+  add_virtual_disk (VirtualDisk vd)
+  {
+    virtual_disks.add(vd);
+    key_hash.put(vd.get_key(), vd);
+  }
+
+  public void
+  add_virtual_block_device (VirtualBlockDevice vbd)
+  {
+    Object hash = get_vbd_hash(vbd.domain, vbd.vbdnum);
+    virtual_block_devices.put(hash, vbd);
+  }
+
+  Object
+  get_vbd_hash (int domain, int vbd_num)
+  {
+    return new Integer(domain * 16 + vbd_num);
+  }
+
+  public void
+  add_free (VirtualDisk vd)
+  {
+    free = vd;
+  }
+
+  public String
+  dump_virtualdisk (int segment)
+  {
+    if (segment < 0 || segment >= virtual_disks.size())
+    {
+      return null;
+    }
+    else
+    {
+      VirtualDisk vd = (VirtualDisk) virtual_disks.get(segment);
+      return (vd.dump(true, true));
+    }
+  }
+
+  public String
+  dump_free()
+  {
+    return(free.dump(true, false));
+  }
+
+  public String
+  dump_virtualdisks()
+  {
+    StringBuffer sb = new StringBuffer();
+
+    for (int i = 0; i < virtual_disks.size(); i++)
+    {
+      VirtualDisk vd = (VirtualDisk) virtual_disks.get(i);
+      if (i == 0)
+      {
+       sb.append(vd.dump(false, true));
+      }
+      sb.append(vd.dump(false, false));
+    }
+
+    return sb.toString();
+  }
+
+  public String
+  dump_virtualblockdevices()
+  {
+    StringBuffer sb = new StringBuffer();
+    boolean first = true;
+
+    for (Enumeration enumeration = virtual_block_devices.elements() ; 
+        enumeration.hasMoreElements() ;) 
+    {
+      VirtualBlockDevice vbd = (VirtualBlockDevice) enumeration.nextElement();
+      if (first)
+      {
+       sb.append(vbd.dump(true));
+       first = false;
+      }
+
+      sb.append(vbd.dump(false));
+    }
+
+    return sb.toString();
+  }
+
+  public void
+  dump_xml(PrintWriter out)
+  {
+    out.println("<free>");
+    free.dump_xml(out);
+    out.println("</free>");
+    out.println("<virtual_disks>");
+    for (int i = 0; i < virtual_disks.size(); i++)
+    {
+      VirtualDisk vd = (VirtualDisk) virtual_disks.get(i);
+      vd.dump_xml(out);
+    }
+    out.println("</virtual_disks>");
+    out.println("<virtual_block_devices>");
+    for (Enumeration enumeration = virtual_block_devices.elements() ; 
+        enumeration.hasMoreElements() ;) 
+    {
+      VirtualBlockDevice vbd = (VirtualBlockDevice) enumeration.nextElement();
+      vbd.dump_xml(out);
+    }
+    out.println("</virtual_block_devices>");
+
+    return;
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XML.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XML.java
new file mode 100755 (executable)
index 0000000..fa11780
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * XML.java
+ * 03.03.26 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import javax.xml.parsers.DocumentBuilder; 
+import javax.xml.parsers.DocumentBuilderFactory; 
+import javax.xml.parsers.FactoryConfigurationError; 
+import javax.xml.parsers.ParserConfigurationException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException; 
+import org.xml.sax.SAXParseException;
+public class
+XML
+{
+  static Document document = null;
+
+  /*
+   * dump partition manager and virtual disk manager state to filename
+   */
+
+  static void
+  dump_state (PartitionManager pm, VirtualDiskManager vdm, String filename)
+  {
+    PrintWriter out;
+
+    try
+    {
+      out = new PrintWriter(new BufferedWriter(new FileWriter(filename)));
+    }
+    catch (IOException e)
+    {
+      System.err.println ("XML.dump_state error [" + filename + "]");
+      System.err.println (e);
+      return;
+    }
+
+    out.println("<?xml version=\"1.0\"?>");
+    out.println("<vdmanager>");
+    pm.dump_xml(out);
+    vdm.dump_xml(out);
+    out.println("</vdmanager>");
+
+    out.close();
+    return;
+  }
+
+  /*
+   * load partition manager and virtual disk manager state from filename
+   */
+  static void
+  load_state (PartitionManager pm, VirtualDiskManager vdm, String filename)
+  {
+    if (document == null)
+    {
+      load_file (filename);
+    }
+
+    XMLHelper.parse(pm, vdm, document);
+  }
+
+  /*
+   * load XML from disk
+   */
+  static void
+  load_file (String filename)
+  {
+    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+    // factory.setNamespaceAware(true);
+    // factory.setValidating(true);
+
+    try
+    {
+      File file = new File(filename);
+
+      DocumentBuilder builder = factory.newDocumentBuilder();
+      document = builder.parse(file);
+    }
+    catch (SAXParseException spe)               /* error generated by parser */
+    {
+      System.err.println ("xml parser exception on line " + 
+                         spe.getLineNumber() + 
+                         " for uri " + spe.getSystemId());
+      System.err.println (spe.getMessage());
+
+      Exception x = spe;
+      if (spe.getException() != null)
+       x = spe.getException();
+      x.printStackTrace();
+      System.exit(1);
+    }
+    catch (SAXException sxe)
+    {
+      Exception e = sxe;
+      if (sxe.getException() != null)
+       e = sxe.getException();
+      e.printStackTrace();
+      System.exit(1);
+    }
+    catch (ParserConfigurationException pce)
+    {
+      pce.printStackTrace();
+    }
+    catch (FileNotFoundException fnfe)
+    {
+      System.err.println ("warning: state file not found [" +
+                         filename + "]");
+    }
+    catch (IOException ioe)
+    {
+      ioe.printStackTrace();
+    }
+    return;
+  }
+}
diff --git a/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XMLHelper.java b/tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/XMLHelper.java
new file mode 100755 (executable)
index 0000000..29ef786
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * XMLHelper.java
+ * 03.03.27 aho creation
+ */
+
+package uk.ac.cam.cl.xeno.vdmanager;
+
+import java.util.Date;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class
+XMLHelper
+{
+  static void
+  dump_document (Document document)
+  {
+    dump_element(document.getDocumentElement(), 0);
+  }
+
+  static void
+  dump_element (Element element, int indent)
+  {
+    NodeList nl = element.getChildNodes();
+
+    System.out.println ("<" + element.getTagName() + ">");
+    dump_nodelist(nl, indent + 1);
+    System.out.println("</" + element.getTagName() + ">");
+  }
+
+  static void
+  dump_nodelist (NodeList nl, int indent)
+  {
+    for (int loop = 0; loop < nl.getLength(); loop++)
+    {
+      Node node = nl.item(loop);
+      switch (node.getNodeType())
+      {
+       case Node.ELEMENT_NODE : 
+       {
+         dump_element((Element)node, indent);
+         break;
+       }
+       case Node.TEXT_NODE :
+       {
+         System.out.println("TEXT: " + node.getNodeValue());
+         break;
+       }
+       default :
+       {
+         System.out.println("NODE: " + node.getNodeType());
+       }
+      }
+    }
+  }
+
+  static Node 
+  get_subnode (String name, Node node) 
+  {
+    if (node.getNodeType() != Node.ELEMENT_NODE) 
+    {
+      System.err.println("Error: Search node not of element type");
+      return null;
+    }
+
+    if (!node.hasChildNodes()) return null;
+
+    NodeList list = node.getChildNodes();
+    for (int i=0; i < list.getLength(); i++) 
+    {
+      Node subnode = list.item(i);
+      if (subnode.getNodeType() == Node.ELEMENT_NODE) 
+      {
+       if (subnode.getNodeName() == name) return subnode;
+      }
+    }
+    return null;
+  }
+
+  static String 
+  get_text (Node node) 
+  {
+    StringBuffer result = new StringBuffer();
+    if (node==null || !node.hasChildNodes()) return "";
+
+    NodeList list = node.getChildNodes();
+    for (int i=0; i < list.getLength(); i++) 
+    {
+      Node subnode = list.item(i);
+      if (subnode.getNodeType() == Node.TEXT_NODE) 
+      {
+       result.append(subnode.getNodeValue());
+      }
+    }
+    return result.toString();
+  }
+
+  static void
+  parse (PartitionManager pm, VirtualDiskManager vdm, Document document)
+  {
+    if (document == null) return;
+
+    /* parse partitions */
+    parse_partitions(pm, document.getElementsByTagName("partition"));
+
+    /* parse virtual disks */
+    NodeList list = document.getElementsByTagName("virtual_disk");
+    for (int i = 0; i < list.getLength(); i++)
+    {
+      Node subnode = list.item(i);
+      String parent = subnode.getParentNode().getNodeName();
+      VirtualDisk vd =  parse_virtual_disk(subnode);
+
+      if (parent.equals("free"))
+      {
+       vdm.add_free(vd);
+      }
+      else if (parent.equals("virtual_disks"))
+      {
+       vdm.add_virtual_disk(vd);
+      }
+      else
+      {
+       System.out.println ("XML parse error: unknown parent for virtual_disk "
+                           + "[" + parent + "]");
+      }
+    }
+
+    /* parse virtual block devices */
+    parse_virtual_block_devices(vdm, document.getElementsByTagName("virtual_block_device"));
+
+    return;
+  }
+
+  static VirtualDisk
+  parse_virtual_disk(Node node)
+  {
+    VirtualDisk vd;
+    Date date = new Date();
+    NodeList list;
+
+    date.setTime(Long.parseLong(XMLHelper.get_text(XMLHelper.get_subnode("expiry", node))));
+    vd = new VirtualDisk(XMLHelper.get_text(XMLHelper.get_subnode("name", node)),
+                        date,
+                        XMLHelper.get_text(XMLHelper.get_subnode("key", node)));
+
+    list = XMLHelper.get_subnode("extents", node).getChildNodes();
+    for (int i = 0; i < list.getLength(); i++)
+    {
+      Node enode = list.item(i);
+
+      if (enode.getNodeType() == Node.ELEMENT_NODE &&
+         enode.getNodeName().equals("extent"))
+      {
+       Extent extent = new Extent();
+
+       extent.disk = Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("disk", enode)));
+       extent.size = Long.parseLong(XMLHelper.get_text(XMLHelper.get_subnode("size", enode)));
+       extent.offset = Long.parseLong(XMLHelper.get_text(XMLHelper.get_subnode("offset", enode)));
+       vd.add_extent(extent);
+      }
+    }
+
+    return vd;
+  }
+
+  static void
+  parse_partitions (PartitionManager pm, NodeList nl)
+  {
+    Partition partition;
+
+    for (int loop = 0; loop < nl.getLength(); loop++)
+    {
+      Node node = nl.item(loop);
+
+      partition = new Partition();
+      partition.major = Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("major", node)));
+      partition.minor = Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("minor", node)));
+      partition.blocks = Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("blocks", node)));
+      partition.start_sect = Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("start_sect", node)));
+      partition.nr_sects = Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("nr_sects", node)));
+      partition.name = XMLHelper.get_text(XMLHelper.get_subnode("name", node));
+
+      pm.add_xeno_partition(partition);
+    }
+  }
+
+  static void
+  parse_virtual_block_devices (VirtualDiskManager vdm, NodeList nl)
+  {
+    VirtualBlockDevice vbd;
+
+    for (int loop = 0; loop < nl.getLength(); loop++)
+    {
+      Node node = nl.item(loop);
+
+      vdm.create_virtual_block_device(XMLHelper.get_text(XMLHelper.get_subnode("key", node)),
+                                     Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("domain", node))),
+                                     Integer.parseInt(XMLHelper.get_text(XMLHelper.get_subnode("vbdnum", node))),
+                                     XMLHelper.get_text(XMLHelper.get_subnode("mode", node)));
+    }
+  }
+}
diff --git a/tools/vdmanager/vdmanager b/tools/vdmanager/vdmanager
new file mode 100755 (executable)
index 0000000..e585624
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# development only
+export ANT_HOME=/anfs/scratch/boulderdash/ach61/jakarta-ant-1.5.1
+export JAVA_HOME=/anfs/scratch/labyrinth/ach61/java-1.4.1
+export PATH=${ANT_HOME}/bin:${JAVA_HOME}/bin:${PATH}
+
+# runtime
+export JAVA_HOME=../jre-1.4.1
+export PATH=${JAVA_HOME}/bin:${PATH}
+if [ -f /var/run/vdmanager.xml ]
+then
+  cp /var/run/vdmanager.xml /var/run/vdmanager.old.xml
+fi
+
+java -jar vdmanager.jar $*
index 156dcbb94c0bc987d6668ebb93494619df648408..cefeef42d28f60a42c3edf46737c655403772b1d 100644 (file)
@@ -202,7 +202,12 @@ static void end_block_io_op(struct buffer_head *bh, int uptodate)
     if ( !uptodate )
     {
         DPRINTK("Buffer not up-to-date at end of operation\n");
-        pending_req->status = 1;
+        pending_req->status = 2;
+    }
+
+    if (pending_req->status)
+    {
+      printk ("Hey! status is %d\n", pending_req->status);
     }
 
     unlock_buffer(pending_req->domain, 
@@ -646,6 +651,7 @@ kdev_t xendev_to_physdev(unsigned short xendev)
         }
         return scsi_devs[xendev];
         
+    case XENDEV_VIRTUAL:
     default:
         DPRINTK("xendev_to_physdev: unknown device %d\n", xendev);
     }
@@ -661,6 +667,11 @@ static void make_response(struct task_struct *p, unsigned long id,
     int position;
     blk_ring_t *blk_ring;
 
+    if (st != 0)
+    {
+      printk("status is %ld\n", st);
+    }
+
     /* Place on the response ring for the relevant domain. */ 
     spin_lock_irqsave(&p->blk_ring_lock, flags);
     blk_ring = p->blk_ring_base;
@@ -711,7 +722,6 @@ void init_blkdev_info(struct task_struct *p)
     p->blkdev_list.next = NULL;
 
     memset(p->segment_list, 0, sizeof(p->segment_list));
-    p->segment_count = 0;
 
     /* Get any previously created segments. */
     xen_refresh_segment_list(p);
@@ -743,5 +753,5 @@ void initialize_block_io ()
 
     xen_segment_initialize();
     
-    add_key_handler('b', dump_blockq, "dump xen ide blkdev stats");     
+    add_key_handler('b', dump_blockq, "dump xen ide blkdev statistics");
 }
index dbfe699030318c5f481f88706ba3a7e8d3a8ecb4..5d26fcc113a2738e74f90b068e8d14bfbb159831 100644 (file)
@@ -36,6 +36,7 @@ int xen_segment_map_request(
     extent_t  *ext;
     int sum, i;
 
+    segment_number &= XENDEV_IDX_MASK;
     if ( segment_number >= XEN_MAX_SEGMENTS ) goto fail;
 
     seg = p->segment_list[segment_number];
@@ -138,7 +139,6 @@ void xen_refresh_segment_list (struct task_struct *p)
             continue;
 
         p->segment_list[xsegments[loop].segment_number] = &xsegments[loop];
-        p->segment_count++;
     }
 }
 
@@ -147,18 +147,23 @@ void xen_refresh_segment_list (struct task_struct *p)
  *
  * return 0 on success, 1 on failure
  *
- * TODO: need to check to see if the DOM#/SEG# combination
- *       already exists. if so, reuse the slot in the segment table.
+ * if we see the same DOM#/SEG# combination, we reuse the slot in
+ * the segment table (overwriting what was there before).
+ * an alternative would be to raise an error if the slot is reused.
+ * bug: we don't free the xtents array when we re-use a slot.
  */
 int xen_segment_create(xv_disk_t *xvd_in)
 {
     int idx;
     int loop;
     xv_disk_t *xvd = map_domain_mem(virt_to_phys(xvd_in));
+    struct task_struct *p;
 
     for (idx = 0; idx < XEN_MAX_SEGMENTS; idx++)
     {
-        if (xsegments[idx].mode == XEN_SEGMENT_UNUSED) break;
+        if (xsegments[idx].mode == XEN_SEGMENT_UNUSED ||
+           (xsegments[idx].domain == xvd->domain &&
+            xsegments[idx].segment_number == xvd->segment)) break;
     }
     if (idx == XEN_MAX_SEGMENTS)
     {
@@ -189,6 +194,18 @@ int xen_segment_create(xv_disk_t *xvd_in)
         }
     }
 
+    /* if the domain exists, assign the segment to the domain */
+    p = current;
+    do
+    {
+      p = p->next_task;
+    } while (p != current && p->domain != xvd->domain);
+
+    if (p->domain == xvd->domain)
+    {
+      p->segment_list[xvd->segment] = &xsegments[idx];
+    }
+
     unmap_domain_mem(xvd);
     return 0;
 }
@@ -222,7 +239,7 @@ static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs)
                    xsegments[loop].num_extents);
             for (i = 0; i < xsegments[loop].num_extents; i++)
             {
-                printk("     ext %d: disk %d, offset 0x%lx, size 0x%lx\n",
+                printk("     extent %d: disk 0x%x, offset 0x%lx, size 0x%lx\n",
                        i, xsegments[loop].extents[i].disk,
                        xsegments[loop].extents[i].offset,
                        xsegments[loop].extents[i].size);
@@ -230,19 +247,19 @@ static void dump_segments(u_char key, void *dev_id, struct pt_regs *regs)
         }
     }
 
-    printk("segments by domain\n");
-    p = current->next_task;
+    printk("segments by domain (index into segments list)\n");
+    p = current;
     do
     {
-        printk("  domain: %d\n", p->domain);
-        for (loop = 0; loop < p->segment_count; loop++)
+        printk("  domain %d: ", p->domain);
+        for (loop = 0; loop < XEN_MAX_SEGMENTS; loop++)
         {
-            printk("    mode:%d domain:%d seg:%d exts:%d\n",
-                   p->segment_list[loop]->mode,
-                   p->segment_list[loop]->domain,
-                   p->segment_list[loop]->segment_number,
-                   p->segment_list[loop]->num_extents);
+         if (p->segment_list[loop])
+         {
+           printk (" %d", p->segment_list[loop] - xsegments);
+         }
         }
+       printk("\n");
         p = p->next_task;
     } while (p != current);
 }
index 0d1cd113cdc3690bcee0d6149a5ff0ecd251f695..36c2b600ebe073bc97df55d58fd878732d6231a7 100644 (file)
@@ -1388,7 +1388,7 @@ static void idedisk_setup (ide_drive_t *drive)
        if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
            (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
                drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-       printk (KERN_INFO "[XEN] %s: %ld sectors", drive->name, capacity);
+       printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
 
        /* Give size in megabytes (MB), not mebibytes (MiB). */
        /* We compute the exact rounded value, avoiding overflow. */
index 555efd9e81f25ba170075647b36dcf62d7290bd0..82ec3a353825fb2ac227f663124197d1358ed691 100644 (file)
@@ -117,8 +117,7 @@ struct task_struct {
     unsigned int blk_resp_prod; /* (private version of) response producer */
     struct list_head blkdev_list;
     spinlock_t blk_ring_lock;
-    segment_t *segment_list[XEN_MAX_SEGMENTS];                        /* vhd */
-    int segment_count;
+    segment_t *segment_list[XEN_MAX_SEGMENTS];                        /* xvd */
 
     /* VM */
     struct mm_struct mm;
index 1c8022375acd98d963b46194e118559d2ebdb322..9de2f0bf96092c766788624aa4d2b921ff4ed341 100644 (file)
@@ -45,7 +45,7 @@ static inline void signal_requests_to_xen(void)
 }
 
 /* Convert from a XenoLinux major device to the Xen-level 'physical' device */
-static inline unsigned short xldev_to_physdev(kdev_t xldev) 
+inline unsigned short xldev_to_physdev(kdev_t xldev) 
 {
     unsigned short physdev = 0;
 
@@ -149,7 +149,6 @@ int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
 
     case BLKRRPART:                               /* re-read partition table */
         DPRINTK_IOCTL("   BLKRRPART: %x\n", BLKRRPART); 
-        if ( !capable(CAP_SYS_ADMIN) ) return -EACCES;
         return xenolinux_block_revalidate(dev);
 
     case BLKSSZGET:
@@ -231,7 +230,11 @@ int xenolinux_block_revalidate(kdev_t dev)
     xl_disk_t *disk = xldev_to_xldisk(dev);
     unsigned long flags;
     int i, partn_shift = PARTN_SHIFT(dev);
+    int xdev = dev & XENDEV_IDX_MASK;
     
+    DPRINTK("xenolinux_block_revalidate: %d %d %d\n", 
+           dev, xdev, XENDEV_IDX_MASK);
+
     spin_lock_irqsave(&io_request_lock, flags);
     if ( disk->usage > 1 )
     {
@@ -242,9 +245,9 @@ int xenolinux_block_revalidate(kdev_t dev)
 
     for ( i = 0; i < (1 << partn_shift); i++ )
     {
-        invalidate_device(dev + i, 1);
-        gd->part[dev + i].start_sect = 0;
-        gd->part[dev + i].nr_sects = 0;
+        invalidate_device(xdev + i, 1);
+        gd->part[xdev + i].start_sect = 0;
+        gd->part[xdev + i].nr_sects = 0;
     }
 
     grok_partitions(gd, MINOR(dev) >> partn_shift,
@@ -438,7 +441,8 @@ static void xlblk_response_int(int irq, void *dev_id, struct pt_regs *ptregs)
         case XEN_BLOCK_READ:
         case XEN_BLOCK_WRITE:
             if ( bret->status )
-                printk(KERN_ALERT "Bad return from blkdev data request\n");
+                printk(KERN_ALERT "Bad return from blkdev data request: %lx\n",
+                      bret->status);
             for ( bh = (struct buffer_head *)bret->id; 
                   bh != NULL; 
                   bh = next_bh )
@@ -491,6 +495,7 @@ int xenolinux_control_msg(int operation, char *buffer, int size)
     /* We copy from an aligned buffer, as interface needs sector alignment. */
     aligned_buf = (char *)get_free_page(GFP_KERNEL);
     if ( aligned_buf == NULL ) BUG();
+    memcpy(aligned_buf, buffer, size);
 
     xlblk_control_msg_pending = 1;
     spin_lock_irqsave(&io_request_lock, flags);
index 48848f901061be05ae103488c908a62b574d09c1..2e86c258310641b62c9beb08a609de54674465b9 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
  * xl_segment.c
  * 
- * Xenolinux virtual block-device driver (vhd).
+ * Xenolinux virtual block-device driver (xvd).
  * 
  */
 
@@ -52,11 +52,11 @@ int __init xlseg_init(void)
     memset(xdi, 0, sizeof(*xdi));
     xenolinux_control_msg(XEN_BLOCK_PROBE_SEG, (char *)xdi, sizeof(*xdi));
 
-    DPRINTK("vhd block device probe:\n");
+    DPRINTK("xvd block device probe:\n");
     for ( i = 0; i < xdi->count; i++ )
     { 
-       DPRINTK("  %2d: type: %d, capacity: %ld\n",
-               i, xdi->disks[i].type, xdi->disks[i].capacity);
+       DPRINTK("  %2d: device: %d, capacity: %ld\n",
+               i, xdi->disks[i].device, xdi->disks[i].capacity);
     }
 
     result = register_blkdev(XLVIRT_MAJOR, XLVIRT_MAJOR_NAME,
index 3149be747b7709274c38445a026ca02b0c6c9c2b..59a3884de95659ab4a08d72e47831a483747bd7c 100644 (file)
@@ -123,7 +123,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
         return count;
     }
 
-    string = get_string(NULL);                             /* look for Segment */
+    string = get_string(NULL);                           /* look for Segment */
     if (string == NULL || (*string != 's' && *string != 'S'))
     {
         printk (KERN_ALERT 
@@ -132,7 +132,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
         return count;
     }
 
-    string = get_string(NULL);                               /* segment number */
+    string = get_string(NULL);                             /* segment number */
     if (string == NULL)
     {
         printk (KERN_ALERT "error: segment number missing\n");
@@ -140,7 +140,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
     }
     xvd.segment = (int) to_number(string);
 
-    string = get_string(NULL);                             /* look for Extents */
+    string = get_string(NULL);                           /* look for Extents */
     if (string == NULL || (*string != 'e' && *string != 'E'))
     {
         printk (KERN_ALERT 
@@ -149,7 +149,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
         return count;
     }
 
-    string = get_string(NULL);                            /* number of extents */
+    string = get_string(NULL);                          /* number of extents */
     if (string == NULL)
     {
         printk (KERN_ALERT "error: number of extents missing\n");
@@ -161,7 +161,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
 
     for (loop = 0; loop < xvd.ext_count; loop++)
     {
-        string = get_string(NULL);                              /* look for Disk */
+        string = get_string(NULL);                          /* look for Disk */
         if (string == NULL || (*string != 'd' && *string != 'D'))
         {
             printk (KERN_ALERT 
@@ -169,15 +169,15 @@ static int proc_write_vhd(struct file *file, const char *buffer,
                     string);
             return count;
         }
-        string = get_string(NULL);                                /* disk number */
+        string = get_string(NULL);                            /* disk number */
         if (string == NULL)
         {
             printk (KERN_ALERT "error: disk number missing\n");
             return count;
         }
-        xvd.extents[loop].disk = (int) to_number(string);
+        xvd.extents[loop].disk = xldev_to_physdev((int) to_number(string));
 
-        string = get_string(NULL);                            /* look for Offset */
+        string = get_string(NULL);                        /* look for Offset */
         if (string == NULL || (*string != 'o' && *string != 'O'))
         {
             printk (KERN_ALERT 
@@ -185,7 +185,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
                     string);
             return count;
         }
-        string = get_string(NULL);                                     /* offset */
+        string = get_string(NULL);                                 /* offset */
         if (string == NULL)
         {
             printk (KERN_ALERT "error: offset missing\n");
@@ -193,7 +193,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
         }
         xvd.extents[loop].offset =  to_number(string);
 
-        string = get_string(NULL);                              /* look for Size */
+        string = get_string(NULL);                          /* look for Size */
         if (string == NULL || (*string != 's' && *string != 'S'))
         {
             printk (KERN_ALERT 
@@ -201,7 +201,7 @@ static int proc_write_vhd(struct file *file, const char *buffer,
                     string);
             return count;
         }
-        string = get_string(NULL);                                       /* size */
+        string = get_string(NULL);                                   /* size */
         if (string == NULL)
         {
             printk (KERN_ALERT "error: extent size missing\n");
diff --git a/xenolinux-2.4.21-pre4-sparse/drivers/block/genhd.c b/xenolinux-2.4.21-pre4-sparse/drivers/block/genhd.c
new file mode 100644 (file)
index 0000000..403d52e
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *  Code extracted from
+ *  linux/kernel/hd.c
+ *
+ *  Copyright (C) 1991-1998  Linus Torvalds
+ *
+ *  devfs support - jj, rgooch, 980122
+ *
+ *  Moved partition checking code to fs/partitions* - Russell King
+ *  (linux@arm.uk.linux.org)
+ */
+
+/*
+ * TODO:  rip out the remaining init crap from this file  --hch
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+
+
+/*
+ * Global kernel list of partitioning information.
+ *
+ * XXX: you should _never_ access this directly.
+ *     the only reason this is exported is source compatiblity.
+ */
+/*static*/ struct gendisk *gendisk_head;
+static struct gendisk *gendisk_array[MAX_BLKDEV];
+static rwlock_t gendisk_lock = RW_LOCK_UNLOCKED;
+
+EXPORT_SYMBOL(gendisk_head);
+
+
+/**
+ * add_gendisk - add partitioning information to kernel list
+ * @gp: per-device partitioning information
+ *
+ * This function registers the partitioning information in @gp
+ * with the kernel.
+ */
+void
+add_gendisk(struct gendisk *gp)
+{
+       struct gendisk *sgp;
+
+       write_lock(&gendisk_lock);
+
+       /*
+        *      In 2.5 this will go away. Fix the drivers who rely on
+        *      old behaviour.
+        */
+
+       for (sgp = gendisk_head; sgp; sgp = sgp->next)
+       {
+               if (sgp == gp)
+               {
+//                     printk(KERN_ERR "add_gendisk: device major %d is buggy and added a live gendisk!\n",
+//                             sgp->major)
+                       goto out;
+               }
+       }
+       gendisk_array[gp->major] = gp;
+       gp->next = gendisk_head;
+       gendisk_head = gp;
+out:
+       write_unlock(&gendisk_lock);
+}
+
+EXPORT_SYMBOL(add_gendisk);
+
+
+/**
+ * del_gendisk - remove partitioning information from kernel list
+ * @gp: per-device partitioning information
+ *
+ * This function unregisters the partitioning information in @gp
+ * with the kernel.
+ */
+void
+del_gendisk(struct gendisk *gp)
+{
+       struct gendisk **gpp;
+
+       write_lock(&gendisk_lock);
+       gendisk_array[gp->major] = NULL;
+       for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
+               if (*gpp == gp)
+                       break;
+       if (*gpp)
+               *gpp = (*gpp)->next;
+       write_unlock(&gendisk_lock);
+}
+
+EXPORT_SYMBOL(del_gendisk);
+
+
+/**
+ * get_gendisk - get partitioning information for a given device
+ * @dev: device to get partitioning information for
+ *
+ * This function gets the structure containing partitioning
+ * information for the given device @dev.
+ */
+struct gendisk *
+get_gendisk(kdev_t dev)
+{
+       struct gendisk *gp = NULL;
+       int maj = MAJOR(dev);
+
+       read_lock(&gendisk_lock);
+       if ((gp = gendisk_array[maj]))
+               goto out;
+
+       /* This is needed for early 2.4 source compatiblity.  --hch */
+       for (gp = gendisk_head; gp; gp = gp->next)
+               if (gp->major == maj)
+                       break;
+out:
+       read_unlock(&gendisk_lock);
+       return gp;
+}
+
+EXPORT_SYMBOL(get_gendisk);
+
+
+/**
+ * walk_gendisk - issue a command for every registered gendisk
+ * @walk: user-specified callback
+ * @data: opaque data for the callback
+ *
+ * This function walks through the gendisk chain and calls back
+ * into @walk for every element.
+ */
+int
+walk_gendisk(int (*walk)(struct gendisk *, void *), void *data)
+{
+       struct gendisk *gp;
+       int error = 0;
+
+       read_lock(&gendisk_lock);
+       for (gp = gendisk_head; gp; gp = gp->next)
+               if ((error = walk(gp, data)))
+                       break;
+       read_unlock(&gendisk_lock);
+
+       return error;
+}
+
+#ifdef CONFIG_PROC_FS
+/* iterator */
+static void *part_start(struct seq_file *s, loff_t *ppos)
+{
+       struct gendisk *gp;
+       loff_t pos = *ppos;
+
+       read_lock(&gendisk_lock);
+       for (gp = gendisk_head; gp; gp = gp->next)
+               if (!pos--)
+                       return gp;
+       return NULL;
+}
+
+static void *part_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       ++*pos;
+       return ((struct gendisk *)v)->next;
+}
+
+static void part_stop(struct seq_file *s, void *v)
+{
+       read_unlock(&gendisk_lock);
+}
+
+static int part_show(struct seq_file *s, void *v)
+{
+       struct gendisk *gp = v;
+       char buf[64];
+       int n;
+
+       if (gp == gendisk_head) {
+               seq_puts(s, "major minor  #blocks  start_sect   nr_sects name"
+#ifdef CONFIG_BLK_STATS
+                           "     rio rmerge rsect ruse wio wmerge "
+                           "wsect wuse running use aveq"
+#endif
+                          "\n\n");
+       }
+
+       /* show the full disk and all non-0 size partitions of it */
+       for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
+               if (gp->part[n].nr_sects) {
+#ifdef CONFIG_BLK_STATS
+                       struct hd_struct *hd = &gp->part[n];
+
+                       disk_round_stats(hd);
+                       seq_printf(s, "%4d  %4d %10d %10ld %s "
+                                     "%d %d %d %d %d %d %d %d %d %d %d\n",
+                                     gp->major, n, gp->sizes[n],
+                                     gp->part[n].start_sect,
+                                     gp->part[n].nr_sects,
+                                     disk_name(gp, n, buf),
+                                     hd->rd_ios, hd->rd_merges,
+#define MSEC(x) ((x) * 1000 / HZ)
+                                     hd->rd_sectors, MSEC(hd->rd_ticks),
+                                     hd->wr_ios, hd->wr_merges,
+                                     hd->wr_sectors, MSEC(hd->wr_ticks),
+                                     hd->ios_in_flight, MSEC(hd->io_ticks),
+                                     MSEC(hd->aveq));
+#else
+                       seq_printf(s, "%4d  %4d %10d %10ld %10ld %s\n",
+                                  gp->major, n, gp->sizes[n],
+                                  gp->part[n].start_sect,
+                                  gp->part[n].nr_sects,
+                                  disk_name(gp, n, buf));
+#endif /* CONFIG_BLK_STATS */
+               }
+       }
+
+       return 0;
+}
+
+struct seq_operations partitions_op = {
+       .start          = part_start,
+       .next           = part_next,
+       .stop           = part_stop,
+       .show           = part_show,
+};
+#endif
+
+extern int blk_dev_init(void);
+extern int net_dev_init(void);
+extern void console_map_init(void);
+extern int atmdev_init(void);
+
+int __init device_init(void)
+{
+       blk_dev_init();
+       sti();
+#ifdef CONFIG_NET
+       net_dev_init();
+#endif
+#ifdef CONFIG_ATM
+       (void) atmdev_init();
+#endif
+#ifdef CONFIG_VT
+       console_map_init();
+#endif
+       return 0;
+}
+
+__initcall(device_init);